"""
进度条组件模块
提供了一个美观、可定制的进度条组件
"""
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, pyqtProperty, QSize, QRect
from PyQt5.QtGui import QPainter, QColor, QFont, QPen, QFontMetrics, QBrush, QPainterPath, QPalette
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QSizePolicy

from component.theme import Theme


class Progress(QWidget):
    """
    进度条组件
    
    提供了一个美观、可定制的进度条，支持动画效果、文本显示和多种样式
    
    参数:
        parent: 父组件
        value: 初始进度值（0-100）
        text_inside: 是否在进度条内显示文本
        show_text: 是否显示文本
        stroke_width: 进度条宽度（像素）
        text_format: 文本格式，使用 {value} 作为进度值占位符
        color: 进度条颜色
        status: 进度条状态，可选值为 "normal", "success", "warning", "danger"
        striped: 是否显示条纹效果
        animated: 是否显示动画效果（仅在 striped=True 时有效）
        circle: 是否为环形进度条
    """
    
    def __init__(self, parent=None, value=0, text_inside=False, show_text=True,
                 stroke_width=6, text_format="{value}%", color=None,
                 status="normal", striped=False, animated=False, circle=False):
        super().__init__(parent)
        
        # 属性初始化
        self._value = max(0, min(100, value))  # 确保值在0-100之间
        self._text_inside = text_inside if not circle else True  # 环形进度条文本始终在内部
        self._show_text = show_text
        self._stroke_width = stroke_width
        self._text_format = text_format
        self._status = status
        self._striped = striped
        self._animated = animated
        self._circle = circle
        
        # 设置颜色
        self._colors = {
            "normal": Theme.PRIMARY,
            "success": Theme.SUCCESS,
            "warning": Theme.WARNING,
            "danger": Theme.DANGER
        }
        self._color = color if color else self._colors.get(status, Theme.PRIMARY)
        
        # 设置布局
        self._layout = QHBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(5)
        
        # 文本标签
        self._text_label = QLabel(self)
        self._text_label.setObjectName("progress_text")
        self._text_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self._text_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        
        # 添加到布局
        if show_text and not self._text_inside and not circle:
            self._layout.addStretch(1)
            self._layout.addWidget(self._text_label)
        else:
            self._text_label.hide()
        
        # 设置样式
        self._apply_style()
        
        # 更新文本
        self._update_text()
        
        # 动画效果
        self._animation = QPropertyAnimation(self, b"animValue")
        self._animation.setEasingCurve(QEasingCurve.OutCubic)
        self._animation.setDuration(300)  # 300毫秒
        
        # 设置大小策略
        if self._circle:
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.setMinimumSize(100, 100)  # 环形进度条最小尺寸
            self.setMaximumSize(100, 100)  # 环形进度条最大尺寸
        else:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
            self.setMinimumHeight(self._stroke_width + 8)  # 进度条高度 + 边距
        
    def _apply_style(self):
        """应用样式"""
        # 文本样式
        text_style = """
            #progress_text {
                color: %s;
                font-size: 14px;
                margin-left: 5px;
            }
        """ % Theme.TEXT_REGULAR
        
        # 应用样式
        self._text_label.setStyleSheet(text_style)
        
        # 设置背景透明
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.setStyleSheet("background: transparent;")
    
    def _update_text(self):
        """更新文本显示"""
        if self._show_text:
            text = self._text_format.format(value=int(self._value))
            self._text_label.setText(text)
    
    def paintEvent(self, event):
        """绘制进度条"""
        super().paintEvent(event)
        
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        if self._circle:
            self._draw_circle_progress(painter)
        else:
            self._draw_bar_progress(painter)
    
    def _draw_bar_progress(self, painter):
        """绘制条形进度条"""
        # 获取组件的几何信息
        rect = self.rect()
        
        # 计算进度条容器的几何信息
        if self._show_text and not self._text_inside:
            # 如果文本在外部，需要减去文本标签的宽度
            text_width = self._text_label.width() + 5  # 5是间距
            container_rect = QRect(rect.x(), rect.y(), rect.width() - text_width, rect.height())
        else:
            container_rect = rect
        
        # 绘制背景
        bg_color = QColor("#EBEEF5")
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(bg_color))
        radius = self._stroke_width // 2
        painter.drawRoundedRect(container_rect, radius, radius)
        
        # 计算进度条宽度
        progress_width = container_rect.width() * (self._value / 100.0)
        
        # 绘制进度条
        if progress_width > 0:
            progress_rect = QRect(container_rect.x(), container_rect.y(), 
                                 int(progress_width), container_rect.height())
            
            # 设置画笔颜色
            painter.setPen(Qt.NoPen)
            painter.setBrush(QBrush(QColor(self._color)))
            
            # 绘制圆角矩形
            if progress_width < 2 * radius:
                # 如果进度条宽度小于直径，使用椭圆
                painter.drawRoundedRect(progress_rect, radius, radius)
            else:
                # 否则使用圆角矩形
                painter.drawRoundedRect(progress_rect, radius, radius)
            
            # 如果需要在进度条内显示文本
            if self._show_text and self._text_inside and progress_width > 40:
                text = self._text_format.format(value=int(self._value))
                painter.setPen(QColor("#FFFFFF"))
                font = QFont()
                font.setPixelSize(12)
                painter.setFont(font)
                
                # 计算文本位置
                fm = QFontMetrics(font)
                text_width = fm.width(text)
                text_height = fm.height()
                
                # 确保文本在进度条内
                if text_width < progress_width - 10:
                    text_x = progress_rect.x() + (progress_width - text_width) / 2
                    text_y = progress_rect.y() + (progress_rect.height() + text_height) / 2 - 2
                    painter.drawText(int(text_x), int(text_y), text)
            
            # 如果需要条纹效果
            if self._striped and progress_width > 20:
                self._draw_stripes(painter, progress_rect)
    
    def _draw_circle_progress(self, painter):
        """绘制环形进度条"""
        # 获取组件的几何信息
        rect = self.rect()
        center_x = rect.center().x()
        center_y = rect.center().y()
        
        # 计算半径（取宽高中的较小值）
        outer_radius = min(rect.width(), rect.height()) / 2 - 5  # 留出一些边距
        inner_radius = outer_radius - self._stroke_width
        
        # 绘制背景圆环
        painter.setPen(Qt.NoPen)
        painter.setBrush(QColor("#EBEEF5"))
        painter.drawEllipse(
            int(center_x - outer_radius),
            int(center_y - outer_radius),
            int(outer_radius * 2),
            int(outer_radius * 2)
        )
        
        # 绘制内部空白区域（挖空中间部分）
        painter.setBrush(QColor(self.palette().color(QPalette.Window)))
        painter.drawEllipse(
            int(center_x - inner_radius),
            int(center_y - inner_radius),
            int(inner_radius * 2),
            int(inner_radius * 2)
        )
        
        # 计算进度扇形的角度
        start_angle = 90 * 16  # 从顶部开始，Qt中角度以1/16度为单位
        span_angle = -self._value * 3.6 * 16  # 负值表示顺时针方向
        
        # 创建进度扇形路径
        if self._value > 0:
            # 设置画笔和画刷
            painter.setPen(Qt.NoPen)
            painter.setBrush(QColor(self._color))
            
            # 使用QPainterPath绘制扇形
            path = QPainterPath()
            
            # 移动到圆环中心
            path.moveTo(center_x, center_y)
            
            # 添加外圆弧
            path.arcTo(
                int(center_x - outer_radius),
                int(center_y - outer_radius),
                int(outer_radius * 2),
                int(outer_radius * 2),
                start_angle / 16,  # 转换回度
                span_angle / 16    # 转换回度
            )
            
            # 添加内圆弧（反方向）
            path.arcTo(
                int(center_x - inner_radius),
                int(center_y - inner_radius),
                int(inner_radius * 2),
                int(inner_radius * 2),
                (start_angle + span_angle) / 16,  # 转换回度
                -span_angle / 16                  # 转换回度，负号表示反方向
            )
            
            # 关闭路径
            path.closeSubpath()
            
            # 绘制路径
            painter.drawPath(path)
        
        # 环形进度条始终在内部显示文本
        if self._show_text:
            text = self._text_format.format(value=int(self._value))
            painter.setPen(QColor(Theme.TEXT_REGULAR))
            font = QFont()
            font.setPixelSize(16)
            painter.setFont(font)
            
            # 计算文本位置
            fm = QFontMetrics(font)
            text_width = fm.width(text)
            text_height = fm.height()
            
            # 绘制文本在圆环中心
            painter.drawText(
                int(center_x - text_width / 2),
                int(center_y + text_height / 3),
                text
            )
    
    def _draw_stripes(self, painter, rect):
        """绘制条纹效果"""
        stripe_color = QColor(255, 255, 255, 50)  # 半透明白色
        painter.setPen(QPen(stripe_color, 10))
        
        # 绘制斜线条纹
        stripe_width = 20
        for x in range(int(rect.x() - stripe_width), int(rect.right()), stripe_width):
            painter.drawLine(
                x, rect.bottom(),
                x + stripe_width, rect.top()
            )
    
    def sizeHint(self):
        """返回建议的大小"""
        if self._circle:
            return QSize(100, 100)
        return QSize(200, self._stroke_width + 8)
    
    # 属性访问器和设置器
    def get_value(self):
        """获取进度值"""
        return self._value
    
    def set_value(self, value):
        """设置进度值（0-100）"""
        # 确保值在0-100之间
        try:
            new_value = max(0, min(100, float(value)))
        except (ValueError, TypeError):
            return
        
        if self._value != new_value:
            # 使用动画效果
            self._animation.setStartValue(self._value)
            self._animation.setEndValue(new_value)
            self._animation.start()
            
            # 直接设置内部变量
            self._value = new_value
            self._update_text()
            self.update()  # 触发重绘
    
    # 使用Python属性
    value = property(get_value, set_value)
    
    # 为QPropertyAnimation定义属性
    @pyqtProperty(float)
    def animValue(self):
        return self._value
    
    @animValue.setter
    def animValue(self, value):
        if self._value != value:
            self._value = value
            self._update_text()
            self.update()
    
    def setColor(self, color):
        """设置进度条颜色"""
        self._color = color
        self.update()
    
    def setStatus(self, status):
        """设置进度条状态"""
        if status in self._colors:
            self._status = status
            self._color = self._colors[status]
            self.update()
    
    def setTextFormat(self, text_format):
        """设置文本格式"""
        self._text_format = text_format
        self._update_text()
        self.update()
    
    def setStriped(self, striped):
        """设置是否显示条纹效果"""
        self._striped = striped
        self.update()
    
    def setAnimated(self, animated):
        """设置是否显示动画效果"""
        self._animated = animated
        self.update()
    
    def setTextInside(self, text_inside):
        """设置是否在进度条内显示文本"""
        if self._text_inside == text_inside:
            return
            
        self._text_inside = text_inside
        
        # 更新布局
        self._layout.removeWidget(self._text_label)
        
        # 清空布局
        while self._layout.count():
            item = self._layout.takeAt(0)
            if item.spacerItem():
                self._layout.removeItem(item)
        
        if self._show_text:
            if text_inside or self._circle:
                self._text_label.hide()
            else:
                self._text_label.show()
                self._layout.addStretch(1)
                self._layout.addWidget(self._text_label)
        
        self.update()
    
    def setShowText(self, show_text):
        """设置是否显示文本"""
        if self._show_text == show_text:
            return
            
        self._show_text = show_text
        
        # 更新布局
        self._layout.removeWidget(self._text_label)
        
        # 清空布局
        while self._layout.count():
            item = self._layout.takeAt(0)
            if item.spacerItem():
                self._layout.removeItem(item)
        
        if show_text:
            if not self._text_inside and not self._circle:
                self._text_label.show()
                self._layout.addStretch(1)
                self._layout.addWidget(self._text_label)
            else:
                self._text_label.hide()
        else:
            self._text_label.hide()
        
        self.update()
    
    def setStrokeWidth(self, stroke_width):
        """设置进度条宽度"""
        self._stroke_width = stroke_width
        if not self._circle:
            self.setMinimumHeight(stroke_width + 8)
        self._apply_style()
        self.update() 